/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.engine.cmd.list;

import cn.easyplatform.contexts.ListContext;
import cn.easyplatform.contexts.RecordContext;
import cn.easyplatform.contexts.WorkflowContext;
import cn.easyplatform.dos.FieldDo;
import cn.easyplatform.dos.Record;
import cn.easyplatform.engine.runtime.datalist.DataListUtils;
import cn.easyplatform.entities.beans.table.TableBean;
import cn.easyplatform.interceptor.AbstractCommand;
import cn.easyplatform.interceptor.CommandContext;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.DropRequestMessage;
import cn.easyplatform.messages.response.SimpleResponseMessage;
import cn.easyplatform.messages.vos.datalist.ListDropVo;
import cn.easyplatform.messages.vos.datalist.ListHeaderVo;
import cn.easyplatform.messages.vos.datalist.ListUpdatableRowVo;
import cn.easyplatform.support.scripting.CompliableScriptEngine;
import cn.easyplatform.support.scripting.ScriptEngineFactory;
import cn.easyplatform.type.*;
import cn.easyplatform.util.MessageUtils;
import cn.easyplatform.util.RuntimeUtils;

import java.util.ArrayList;
import java.util.List;


/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class DropCmd extends AbstractCommand<DropRequestMessage> {

    /**
     * @param req
     */
    public DropCmd(DropRequestMessage req) {
        super(req);
    }

    @Override
    public IResponseMessage<?> execute(CommandContext cc) {
        WorkflowContext ctx = cc.getWorkflowContext();
        ListContext source = null;
        ListDropVo vo = req.getBody();
        if (!Strings.isBlank(vo.getSourceId())) {
            source = ctx.getList(vo.getSourceId());
            if (source == null)
                return MessageUtils.dataListNotFound(vo.getSourceId());
        }
        ListContext target = ctx.getList(vo.getTargetId());
        if (target == null)
            return MessageUtils.dataListNotFound(vo.getTargetId());
        TableBean tb = cc.getEntity(target.getBean().getTable());
        if (tb == null)
            return MessageUtils.entityNotFound(EntityType.TABLE.getName(),
                    target.getBean().getTable());
        List<ListRowVo> result = new ArrayList<ListRowVo>();
        RecordContext clone = null;
        for (ListRowVo row : vo.getData()) {
            RecordContext src = null;
            if (source == null) {
                if (clone == null)
                    clone = cc.getWorkflowContext().getRecord().clone();
                clone.setData(RuntimeUtils.createRecord(row.getData()));
                src = clone;
            } else
                src = source.createRecord(DataListUtils.getRecord(cc,
                        source, source.isCustom() ? row.getData() : row.getKeys()));
            RecordContext rc = null;
            if (!Strings.isBlank(vo.getFilter()) && source != null) {
                CompliableScriptEngine engine = ScriptEngineFactory
                        .createCompilableEngine(cc, vo.getFilter());
                try {
                    for (RecordContext record : target.getRecords()) {
                        Object b = engine.eval(src, record);
                        if (b != null && (b instanceof Boolean) && (Boolean) b) {
                            rc = record;
                            break;
                        }
                    }
                } finally {
                    engine.destroy();
                    engine = null;
                }
            }
            boolean appendFlag = rc == null;
            boolean createFlag = false;
            if (appendFlag) {
                rc = target.createRecord(RuntimeUtils.createRecord(cc, tb,
                        tb.isAutoKey()));
                List<ListHeaderVo> headers = target.getHeaders();
                int size = headers.size();
                for (int i = 0; i < size; i++) {
                    ListHeaderVo hv = headers.get(i);
                    if (Strings.isBlank(hv.getField()) && hv.getType() != null) {
                        FieldDo var = new FieldDo(hv.getType());
                        var.setName(hv.getName());
                        var.setScope(ScopeType.PRIVATE);
                        if (hv.getType() == FieldType.NUMERIC) {
                            var.setDecimal(2);
                            var.setLength(19);
                        }
                        rc.setVariable(var);
                    }
                }
                if (!Strings.isBlank(target.getBeforeLogic())) {
                    RecordContext[] rcs = new RecordContext[2];
                    if (!Strings.isBlank(target.getHost())) {
                        ListContext fc = ctx.getList(target.getHost());
                        if (fc == null)
                            return MessageUtils.dataListNotFound(target
                                    .getHost());
                        Object[] fromKeys = (Object[]) vo.getKey();
                        RecordContext r = fc.getRecord(fromKeys);
                        if (r == null && fc.getType().equals(Constants.CATALOG)) {
                            Record record = DataListUtils.getRecord(cc, fc,
                                    fromKeys);
                            r = fc.createRecord(fromKeys, record);
                            r.setParameter("815", false);
                            r.setParameter("814", "R");
                            fc.appendRecord(r);
                        }
                        if (r == null)
                            return MessageUtils.recordNotFound(fc.getBean()
                                    .getTable(), Lang.concat(fromKeys)
                                    .toString());
                        rcs[0] = r;
                    } else
                        rcs[0] = ctx.getRecord();
                    rcs[1] = rc;
                    String code = RuntimeUtils.eval(cc,
                            target.getBeforeLogic(), rcs);
                    if (!code.equals("0000"))
                        return MessageUtils.byErrorCode(cc, rc, ctx.getId(),
                                code);
                }
                rc.setParameter("814", "C");
                rc.setParameter("815", true);
                createFlag = true;
            } else if (rc.getParameterAsChar("814") == 'D') {
                rc.setParameter("814", 'U');
                createFlag = true;
            }
            String mapping = source == null ? vo.getFilter() : source.getBeforeLogic();
            String code = RuntimeUtils.eval(cc, mapping,
                    new RecordContext[]{src, rc});
            if (!code.equals("0000"))
                return MessageUtils.byErrorCode(cc, rc, ctx.getId(), code);
            if (appendFlag)
                target.appendRecord(rc, false);
            if (!Strings.isBlank(target.getOnRow())) {
                code = RuntimeUtils.eval(cc, target.getBean().getOnRow(), rc);
                if (!code.equals("0000"))
                    return MessageUtils.byErrorCode(cc, rc, ctx.getId(), code);
            }
            result.add(new ListUpdatableRowVo(rc.getKeyValues(), DataListUtils
                    .wrapRow(cc, target, rc), createFlag, rc
                    .getParameterAsBoolean("853")));
        }
        return new SimpleResponseMessage(result);
    }

    @Override
    public String getName() {
        return "list.Drop";
    }
}
